package wangjg.commons.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;

@SuppressWarnings("unchecked")
public class BasicHibernateDAO<T, ID extends Serializable> extends AbstractBasicAO<T, ID> {
	private static final Logger log = LoggerFactory.getLogger(BasicHibernateDAO.class);
	@Autowired
	protected SessionFactory sessionFactory;
	
	protected Class<T> persistentClass;

	public BasicHibernateDAO() {
		Type type = getClass().getGenericSuperclass();
		if(!(type instanceof ParameterizedType)){// for AOP
			type = getClass().getSuperclass().getGenericSuperclass();
		}
		ParameterizedType pt = (ParameterizedType)type;
		Type[] ta = pt.getActualTypeArguments();
		this.persistentClass = (Class<T>) ta[0];
	}

	/**
	 * 取得当前Session.
	 */
	protected Session getSession() {
		return sessionFactory.getCurrentSession();
	}
	
	int _________________;
	
	/**
	 * 保存新增对象.
	 */
	public ID save(final T entity) {
		ID id = (ID) getSession().save(entity);
		return id;
	}
	
	/**
	 * 修改对象
	 */
	public void update(final T entity) {
		getSession().update(entity);
		log.debug("update entity: "+entity);
	}

	/**
	 * 保存新增或修改对象.
	 */
	public void saveOrUpdate(final T entity) {
		getSession().saveOrUpdate(entity);
		log.debug("save entity:"+entity);
	}

	/**
	 * 删除对象.
	 * 
	 * @param entity
	 *            对象必须是session中的对象或含id属性的transient对象.
	 */
	public void delete(final T entity) {
		getSession().delete(entity);
		log.debug("delete entity: "+entity);
	}
	public void delete(ID id) {
		this.delete(this.get(id));
	}
	//---------------------------
	
	/**
	 * 根据属性返回唯一实体对象
	 * @param propertyName
	 * @param value
	 * @return
	 */
	public T findByProperty(String propertyName, Object value) {
		Criterion criterion = Restrictions.eq(propertyName, value);
		return (T)findUniqueByCriterions(criterion);
	}

	/**
	 * 根据属性查询数量
	 * @param propertyName
	 * @param propertyValue
	 * @return
	 */
	public <N extends Number> N findCountByProperty(String propertyName, Object propertyValue){
		this.checkProperty(propertyName);
		String hql = "select count(*) from "+this.persistentClass.getSimpleName()+" where "+propertyName+"=?";
		Object o = this.queryUnique(hql, propertyValue);
		N count = (N)o;
		return count;
	}

	/**
	 * 根据属性查询列表
	 * @param propertyName
	 * @param propertyValue
	 * @return
	 */
	public List<T> findListByProperty(String propertyName, Object propertyValue){
		return this.findListByProperty(propertyName, propertyValue, null, null, null, null);
	}

	/**
	 * 根据属性查询列表
	 */
	public List<T> findListByProperty(String propertyName, Object propertyValue, String orderby, Boolean asc, Integer firstResult, Integer maxResults){
		this.checkProperty(propertyName);
		String hql = " from "+this.persistentClass.getSimpleName()+" where "+propertyName+"=?";
		if(orderby!=null){
			this.checkProperty(orderby);
			hql += " order by "+orderby;
			hql += (Boolean.TRUE.equals(asc)?" asc":" desc");
		}
		if(firstResult==null && maxResults==null){
			List<T> result = this.query(hql, propertyValue);
			return result;
		}else{
			List<T> result = this.query(firstResult, maxResults, hql, propertyValue);
			return result;
		}
	}

	public List findPropertyList(String returnProperty, String fieldname, Object value){
		return this.findPropertyList(returnProperty, true, fieldname, value, null, null, null, null);
	}

	/**
	 * 查询属性列表
	 */
	public List findPropertyList(String returnProperty, boolean distinct, String filterProperty, Object filterValue ,String orderby, Boolean asc, Integer firstResult, Integer maxResults){
		this.checkProperty(returnProperty);
		this.checkProperty(filterProperty);
		String hql = "select "+(distinct?"distinct ":"")+returnProperty+" from "+this.persistentClass.getSimpleName();
		if(filterProperty!=null && filterValue!=null){
			hql += " where "+filterProperty+"=?";	
		}
		if(orderby!=null){
			this.checkProperty(orderby);
			String order = (Boolean.TRUE.equals(asc) ? " order by "+orderby+" asc" : " order by "+orderby+" desc");
			hql += order;
		}
		List result = null;
		if(filterProperty!=null && filterValue!=null){
			if(firstResult!=null && maxResults!=null){
				result = this.query(firstResult, maxResults, hql, filterValue);
			}else{
				result = this.query(hql, filterValue);
			}
		}else{
			if(firstResult!=null && maxResults!=null){
				result = this.query(firstResult, maxResults, hql);
			}else{
				result = this.query(hql);
			}
		}
		return result;
	}

	/**
	 * 按HQL查询对象列表
	 * @param hql
	 * @param values
	 * @return 对象集合
	 */
	protected List query(final String hql, final Object... values) {
		return createQuery(hql, values).list();
	}
	
	protected List query(int firstResult, int maxResults, final String hql, final Object... values) {
		Query query = createQuery(hql, values);
		query.setFirstResult(firstResult);
		query.setMaxResults(maxResults);
		return query.list();
	}
	
	/**
	 * 按HQL查询唯一对象.
	 * 
	 * @param values
	 * 数量可变的参数,按顺序绑定.
	 */
	protected Object queryUnique(final String hql, final Object... values) {
		return createQuery(hql, values).uniqueResult();
	}

	protected int executeUpdate(final String hql, final Object... values) {
		return createQuery(hql, values).executeUpdate();
	}

	//---------------------------

	protected T get(ID id) {
		return (T) getSession().get(persistentClass, id);
	}

	protected T load(ID id) {
		return (T) getSession().load(persistentClass, id);
	}

	/**
	 * 合并对象.
	 */
	protected void merge(final T entity) {
		getSession().merge(entity);
		log.debug("merge entity:"+entity);
	}

	/**
	 * 根据查询HQL与参数列表创建Query对象.
	 * 本类封装的find()函数全部默认返回对象类型为T,当不为T时使用本函数.
	 * @param values 数量可变的参数,按顺序绑定.
	 */
	protected Query createQuery(final String queryString, final Object... values) {
		Session session = getSession();
		Assert.hasText(queryString, "queryString不能为空");
		Query query = session.createQuery(queryString);
		if (values != null) {
			for (int i = 0; i < values.length; i++) {
				query.setParameter(i, values[i]);
			}
		}
		return query;
	}

	//---------------------------
	
	/**
	 * @param criterions
	 * @return
	 */
	private Object findUniqueByCriterions(Criterion... criterions) {
		Criteria crit = this.createCriteria(criterions);
		return crit.uniqueResult();
	}

	/**
	 * @param criterions
	 * @return
	 */
	private List<T> findListByCriterions(Criterion... criterions) {
		Criteria crit = this.createCriteria(criterions);
		return crit.list();
	}

	/**
	 * @param criterions
	 * @return
	 */
	private Criteria createCriteria(final Criterion... criterions) {
		Criteria criteria = getSession().createCriteria(persistentClass);
		for (Criterion c : criterions) {
			criteria.add(c);
		}
		return criteria;
	}

}
